package web

import (
	"gin/webook/internal/domain"
	"gin/webook/internal/service"
	"gin/webook/internal/web/validate"
	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
	"net/http"
	"regexp"
)

const (
	emailRegexPattern    = `^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$`
	passwordRegexPattern = `^(?![a-zA-Z]+$)(?!\\d+$)(?![^\\da-zA-Z\\s]+$).{1,9}$`
)

type UserHandler struct {
	svc *service.UserService
}

func NewUserHandler(svc *service.UserService) *UserHandler {
	return &UserHandler{svc: svc}
}
func (h *UserHandler) RegisterRoutes(server *gin.Engine) {
	ug := server.Group("user")

	ug.POST("signup", h.SignUp)
	ug.POST("login", h.Login)
	ug.POST("edit", h.Edit)
	ug.GET("profile", h.Profile)
}

func (h *UserHandler) SignUp(ctx *gin.Context) {
	type SinUpReq struct {
		Email           string `json:"email"`
		Password        string `json:"password"`
		ConfirmPassword string `json:"confirmPassword"`
	}

	var req SinUpReq
	err := ctx.Bind(&req)
	if err != nil {
		return
	}

	isEmail, err := regexp.Match(emailRegexPattern, []byte(req.Email))
	if err != nil {
		ctx.JSON(http.StatusOK, "非法邮箱格式")
		return
	}
	if !isEmail {
		ctx.JSON(http.StatusOK, "非法邮箱格式")
		return
	}

	password, err := regexp.Match(passwordRegexPattern, []byte(req.Password))
	if err != nil {
		ctx.String(http.StatusOK, "非法密码格式")
		return
	}
	if !password {
		ctx.String(http.StatusOK, "非法密码格式")
		return
	}

	if req.Password != req.ConfirmPassword {
		ctx.JSON(http.StatusOK, "两次密码不一致")
		return
	}

	err = h.svc.SignUp(ctx, domain.User{
		Email:    req.Email,
		Password: req.Password,
	})
	switch err {
	case nil:
		ctx.JSON(http.StatusOK, "注册成功")
		return
	case service.ErrDuplicateEmail:
		ctx.JSON(http.StatusOK, "邮箱已存在")
		return
	default:
		ctx.JSON(http.StatusOK, "注册失败")
		return
	}
}

func (h *UserHandler) Login(ctx *gin.Context) {
	type LoginReq struct {
		Email    string `json:"email"`
		Password string `json:"password"`
	}

	var req LoginReq
	err := ctx.Bind(&req)
	if err != nil {
		return
	}

	u, err := h.svc.Login(ctx, req.Email, req.Password)
	switch err {
	case nil:
		session := sessions.Default(ctx)
		session.Set("userId", u.Id)
		session.Options(sessions.Options{
			//十五分钟
			MaxAge: 900,
		})
		err := session.Save()
		if err != nil {
			ctx.JSON(http.StatusOK, "登录失败")
			return
		}
		ctx.JSON(http.StatusOK, "登录成功")
		return
	case service.ErrInvalidUserOrPassword:
		ctx.JSON(http.StatusOK, "用户名或密码不对")
		return
	default:
		ctx.JSON(http.StatusOK, "登录失败")
		return
	}
}

func (h *UserHandler) Profile(ctx *gin.Context) {
	uid := sessions.Default(ctx).Get("userId")

	userInfo, err := h.svc.GetUserInfo(ctx, uid.(int64))
	if err != nil {
		ctx.JSON(http.StatusOK, "用户不存在")
		return
	}

	ctx.JSON(http.StatusOK, userInfo)
}

func (h *UserHandler) Edit(ctx *gin.Context) {

	var req validate.ProfileReq
	err := ctx.Bind(&req)
	if err != nil {
		return
	}

	uid := sessions.Default(ctx).Get("userId")

	userInfo, err := h.svc.GetUserInfo(ctx, uid.(int64))
	if err != nil {
		ctx.JSON(http.StatusOK, "用户不存在")
		return
	}

	userInfo, err = h.svc.UpdateUserInfo(ctx, uid.(int64), req)
	if err != nil {
		ctx.JSON(http.StatusOK, "保存用户信息失败")
		return
	}

	ctx.JSON(http.StatusOK, userInfo)

}
